"""
    Database access module
"""

import threading
import traceback
import gobject
from pysqlite2 import dbapi2 as sqlite
from . import exceptions
from . import log
from . import strunicode

default_db_path = None
connections_pool = dict()

def initialize(db_path):
    """
        Set default path to database
    """
    global default_db_path

    #db = get_connection(db_path)
    default_db_path = db_path


def init_connection(db):
    cursor = db.cursor()
    cursor.execute("PRAGMA synchronize=OFF")
    #cursor.execute("PRAGMA auto_vacuum=1")
    cursor.execute("PRAGMA case_sensitive_like=0")
    cursor.execute("PRAGMA count_changes=0")
    cursor.execute("PRAGMA cache_size=5000")
    cursor.execute("PRAGMA temp_store=MEMORY")
    cursor.execute("PRAGMA fullsync=0")
    cursor.close()
    
    # set other sqlite settings
    #sqlite.register_adapter("str", strunicode.str2ustr)
    #sqlite.register_converter("str", strunicode.ustr2str)

def sqlite_isubstr(x, y):
    """
    Return True if x is substring of y, non case sensitive.
    """
    if y is None:
        return False
    
    return y.upper().find(x.upper()) >= 0

def get_connection(db_path=None):
    """
        Return database connection, threads aware function
    """
    global connections_pool

    if db_path is None and default_db_path is None:
        raise exceptions.DbError("Path to database is not specified!")

    if db_path is None:
        db_path = default_db_path

    # detect current thread
    thread_name = threading.currentThread().getName()

    if connections_pool.has_key(db_path) \
        and connections_pool[db_path].has_key(thread_name):
        return connections_pool[db_path][thread_name]

    # create connection and put it in the pool    
    try:
        log.debug("Creating connection for thread `%s' and path `%s'" % (thread_name, db_path))
        db = sqlite.connect(db_path, check_same_thread=False)
        init_connection(db)
        db.create_function('isubstr', 2, sqlite_isubstr)
        # FIXME line below is added to prevent error:
        # "OperationalError: Could not decode to UTF-8 column"
        # Use unicode strings instead.
        db.text_factory = unicode
    except sqlite.OperationalError, e:
        raise exceptions.DbError(str(e))
    
    if not connections_pool.has_key(db_path):
        connections_pool[db_path] = dict()

    connections_pool[db_path][thread_name] = db
    return db

def close_connection(db_path=None):
    """
        Close connection to the database
    """
    # detect current thread
    thread_name = threading.currentThread().getName()

    if connections_pool.has_key(db_path):
        connections_pool[db_path][thread_name].close()
        del connections_pool[db_path]

def prepare_sql_file(file):
    lines = []
    for line in open(file):
        if not line.startswith("--"):
            lines.append(line)

    sql = "".join(lines)
    sql = sql.replace("\n", "")
    return sql.split(";")


def execute(query, args=None, cursor=None, db=None):
    if args is None:
        args = []
        
    if cursor is None and db is None:
        raise exceptions.DbError("database.execute() failed, db or cursor must be set!")

    if cursor is None:
        cursor = db.cursor()
        
    if db is None:
        db = cursor.connection
    
    try:
        #log.debug("Execute query: %s" % query)
        cursor.execute(query, args)
    except Exception, e:
        #traceback.print_exc()
        log.error(query)
        log.error("Arguments: %s " % str(args))
        raise exceptions.DbError(str(e))

def vacuum_database(db=None):
    cursor = db.cursor()
    cursor.execute("VACUUM")
    
def executemany(query, argslist, cursor=None, db=None):
    if cursor is None and db is None:
        raise exceptions.DbError("database.executemany() failed, db or cursor must be set!")

    if cursor is None:
        cursor = db.cursor()
    
    try:
        #log.debug("Execute multiple query: %s" % query)
        cursor.executemany(query, argslist)
    except Exception, e:
        #traceback.print_exc()
        log.error(query)
        log.error("Arguments: %s " % argslist)
        raise exceptions.DbError(str(e))

def last_insert_id(cursor):
    cursor.execute("SELECT LAST_INSERT_ROWID()")
    return cursor.fetchone()[0]

def import_sql_file(path, repl=None, db_path=None):
    """
        Executes SQL code from file
    """
    if repl is None:
        repl = dict()
        
    db = get_connection(db_path)

    lines = prepare_sql_file(path)

    for line in lines:
        line = line % repl
        if line.strip():
            # i.e. line is not empty
            execute(line, db=db)
    db.commit()
